package com.msk.third.service;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.msk.common.utils.DictUtils;
import com.msk.common.utils.StringUtils;
import com.msk.sys.utils.DictMskUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Description OSS后台服务
 * @Author zlf
 * @Date 2023/7/14 17:47
 */
@Service
public class OssServerService {
    // endpoint以杭州为例，其它region请按实际情况填写
    protected String endpoint;
    // accessKey
    protected String accessKeyId;

    protected String accessKeySecret;
    //空间
    protected String bucketName;

    //文件存储目录
    protected String fileDir;

    private OSS ossClient;

    private OSS getOssClient() {
        if (ossClient == null) {
            ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        }
        return ossClient;
    }

    @PostConstruct
    public void initParam() {
        endpoint = DictMskUtils.getDictValue("endpoint","ali_oss_config","");;
        accessKeyId = DictMskUtils.getDictValue("accessKeyId","ali_oss_config","");
        accessKeySecret = DictMskUtils.getDictValue("accessKeySecret","ali_oss_config","");
        bucketName = DictMskUtils.getDictValue("bucketName","ali_oss_config","");
        fileDir = DictMskUtils.getDictValue("fileDir","ali_oss_config","");
    }

    /**
     * 上传文件
     *
     * @param url
     * @param fileName
     */
    public String uploadFile2Oss(String url, String fileName) throws Exception{
        File fileOnServer = new File(url);
        FileInputStream fin = new FileInputStream(fileOnServer);
        this.uploadFile2OSS(fin, fileName);
        return this.getFileUrl(fileName);
    }

    /**
     * 上传文件
     * @param file
     * @param fileName
     * @return
     * @throws Exception
     */
    public String uploadFile2Oss(File file, String fileName) throws Exception{
        InputStream inputStream = new FileInputStream(file);
        this.uploadFile2OSS(inputStream, fileName);
        return this.getFileUrl(fileName);
    }

    /**
     * 上传文件
     * @param is
     * @param fileName
     * @return
     * @throws Exception
     */
    public String uploadInputStream2Oss(InputStream is,String fileName) {
        this.uploadFile2OSS(is, fileName);
        return this.getFileUrl(fileName);
    }

    /**
     * 上传文件
     * @param is
     * @param fileName
     * @param uploadDir
     * @return
     * @throws Exception
     */
    public String uploadInputStream2Oss(InputStream is,String fileName, String uploadDir) {
        this.uploadFile2OSS(is, fileName, uploadDir);
        return this.getFileUrl(fileName);
    }

    /**
     * 删除文件
     * @param fileUrl 带域名的访问全地址
     */
    public void deleteFile(String fileUrl) throws Exception{
        fileUrl = fileUrl.split("\\?")[0];
        String[] urls = fileUrl.split("/");
        StringBuffer filePath = new StringBuffer();
        for(String mkdir : urls){
            if(StringUtils.isNotEmpty(mkdir)){
                if(!mkdir.equals("http:") && mkdir.indexOf("aliyuncs.com")<0){
                    if(filePath.length()>0){
                        filePath.append("/");
                    }
                    filePath.append(mkdir);
                }
            }
        }

        getOssClient().deleteObject(bucketName, filePath.toString());
    }
    /**
     * 查询指定bucket空间文件列表
     * @return
     */
    public List<String> getFileList(){
        List<String> fileList = new ArrayList<>();
        int maxKeys = 100;
        ListObjectsRequest request = new ListObjectsRequest(bucketName).withMaxKeys(maxKeys);
        request.setMaxKeys(maxKeys);
        nextFileList(request,fileList);
        return fileList;
    }

    /**
     * 获得文件路径
     *
     * @param fileUrl
     * @return
     */
    private String getFileUrl(String fileUrl) {
        if (fileUrl!=null && fileUrl!="") {
            String[] split = fileUrl.split("/");
            return this.getUrl(this.getDateMkdir() + split[split.length - 1]);
        }
        return null;
    }

    /**
     * 获得文件路径
     *
     * @param fileUrl
     * @param uploadDir
     * @return
     */
    private String getFileUrl(String fileUrl, String uploadDir) {
        if (fileUrl!=null && fileUrl!="") {
            String[] split = fileUrl.split("/");
            return this.getUrl(this.getDateMkdir(uploadDir) + split[split.length - 1]);
        }
        return null;
    }

    /**
     * 上传到OSS服务器  如果同名文件会覆盖服务器上的
     *
     * @param instream 文件流
     * @param fileName 文件名称 包括后缀名
     * @return 出错返回"" ,唯一MD5数字签名
     */
    private String uploadFile2OSS(InputStream instream, String fileName) {
        String ret = "";
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            //上传文件
            PutObjectResult putResult = getOssClient().putObject(bucketName, this.getDateMkdir() + fileName, instream, objectMetadata);
            ret = putResult.getETag();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * 上传到OSS服务器  如果同名文件会覆盖服务器上的
     *
     * @param instream 文件流
     * @param fileName 文件名称 包括后缀名
     * @param uploadDir 上传目录
     * @return 出错返回"" ,唯一MD5数字签名
     */
    private String uploadFile2OSS(InputStream instream, String fileName, String uploadDir) {
        String ret = "";
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            //上传文件
            PutObjectResult putResult = getOssClient().putObject(bucketName, this.getDateMkdir(uploadDir) + fileName, instream, objectMetadata);
            ret = putResult.getETag();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * 循环获取文件列表
     * @param fileList
     * @return
     */
    private void nextFileList(ListObjectsRequest request,List<String> fileList) {
        ObjectListing objectListing = getOssClient().listObjects(request);
        List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
        for (OSSObjectSummary s : sums) {
            fileList.add(s.getKey());
        }
        //下一次列举文件的起点
        String end = objectListing.getNextMarker();
        if(end!=null){
            request.setMarker(end);
            nextFileList(request,fileList);
        }
    }
    /**
     * Description: 判断OSS服务文件上传时文件的contentType
     *
     * @param FilenameExtension 文件后缀
     * @return String
     */
    private static String getcontentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".xls")) {
            return "application/vnd.ms-excel";
        }
        if (FilenameExtension.equalsIgnoreCase(".xlsx")) {
            return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        }

        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        if (FilenameExtension.equalsIgnoreCase(".zip")) {
            return "application/zip";
        }
        if (FilenameExtension.equalsIgnoreCase(".rar")) {
            return "application/x-rar-compressed";
        }
        if (FilenameExtension.equalsIgnoreCase(".pdf")) {
            return "application/pdf";
        }
        if (FilenameExtension.equalsIgnoreCase(".mp4")) {
            return "video/mp4";
        }
        if (FilenameExtension.equalsIgnoreCase(".mp3")) {
            return "audio/mp3";
        }
        if (FilenameExtension.equalsIgnoreCase(".wav")) {
            return "audio/wav";
        }
        if (FilenameExtension.equalsIgnoreCase(".wma")) {
            return "audio/x-ms-wma";
        }
        if (FilenameExtension.equalsIgnoreCase(".m4a")) {
            return "audio/m4a";
        }
        if (FilenameExtension.equalsIgnoreCase(".aac")) {
            return "audio/aac";
        }
        if (FilenameExtension.equalsIgnoreCase(".amr")) {
            return "audio/amr";
        }

        if (FilenameExtension.equalsIgnoreCase(".act")) {
            return "audio/act";
        }
        if (FilenameExtension.equalsIgnoreCase(".adpcm")) {
            return "audio/adpcm";
        }
        if (FilenameExtension.equalsIgnoreCase(".pcm")) {
            return "audio/pcm";
        }
        return "image/jpeg";
    }

    /**
     * 获得url链接
     *
     * @param key
     * @return
     */
    public String getUrl(String key) {
        // 设置URL过期时间为100年  3600l* 1000*24*365*100
        Date expiration = new Date(new Date().getTime() + 3600l * 1000 * 24 * 365 * 100);
        // 生成URL
        URL url = getOssClient().generatePresignedUrl(bucketName, key, expiration);
        if (url != null) {
            String fileOssUrl = url.toString();
            if (StringUtils.isNotEmpty(fileOssUrl)) {
                if (fileOssUrl.startsWith("http://")) {
                    fileOssUrl = fileOssUrl.replaceAll("http://", "https://");
                }
                if (fileOssUrl.lastIndexOf("?") != -1) {
                    String [] urlArray = fileOssUrl.split("\\?");
                    fileOssUrl = urlArray[0];
                }
            }
            return fileOssUrl;
        }
        return null;
    }

    /**
     * 获取当天的目录名称
     * @return
     */
    private String getDateMkdir(){
        SimpleDateFormat ymd = new SimpleDateFormat("yyyyMMdd");
        return fileDir + ymd.format(new Date()) + "/";
    }

    /**
     * 获取上传的目录名称
     * @return
     */
    private String getDateMkdir(String uploadDir){
        SimpleDateFormat ymd = new SimpleDateFormat("yyyyMMdd");
        String uploadDirName = ymd.format(new Date());
        if (StringUtils.isNotBlank(uploadDir)) {
            uploadDirName = uploadDir;
        }
        return fileDir + uploadDirName + "/";
    }
}
